package com.sap.apitest2.model;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sap.apitest2.entity.AbstractEntity;
import com.sap.apitest2.entity.Case;
import com.sap.apitest2.entity.Param;
import com.sap.apitest2.entity.Profile;
import com.sap.apitest2.entity.Result;
import com.sap.apitest2.entity.Step;
import com.sap.apitest2.entity.Subcase;


public class CommonProcessJohn {
	final static Logger logger = LoggerFactory
			.getLogger(CommonProcessJohn.class);

	public static void saveEntity(AbstractEntity entity) {
		Transaction tx = null;
		Session session = SessionFactoryUtil.getInstance().getCurrentSession();
		try {
			tx = session.beginTransaction();
			/*
			 * AbstractEntity target =
			 * (AbstractEntity)session.get(entity.getClass(), entity.getKey());
			 * if(target!=null) {
			 * 
			 * }
			 */
			if(entity.getKey()!=null && entity.getKey()>0) {
				AbstractEntity target = (AbstractEntity)session.get(entity.getClass(), entity.getKey());
				if(target!=null) {
					target.acceptValue(entity);
					session.update(target);
				}
			}
			else {
				session.save(entity);
			}
			tx.commit();
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					// Second try catch as the rollback could fail as well
					tx.rollback();
				} catch (HibernateException e1) {
					logger.debug("Error rolling back transaction");
				}
				// throw again the first exception
				// throw e;
			}
			throw e;
		}
	}
	
	
	public static <T extends AbstractEntity> void saveEntities(Long parentId, Collection<T> entities, Collection<T> exists)throws Exception{
		
		Map<Long, T> compare = new HashMap<Long, T>();
		
		if(entities!=null){
			for(T entity : entities){
				compare.put(entity.getKey(), entity);
			}
		}
		if(exists!=null){
			for(T step : exists){
				if(compare.get(step.getKey())==null){
					removeEntity(step);
				}
			}
		}
		if(entities!=null){
			for(T entity : entities){
				saveEntity(entity);
			}
		}
	}

	public static void removeEntity(AbstractEntity entity) throws Exception {
		Transaction tx = null;
		Session session = SessionFactoryUtil.getInstance().getCurrentSession();
		try {
			tx = session.beginTransaction();
			AbstractEntity result = (AbstractEntity) session.get(
					entity.getClass(), entity.getKey());

			session.delete(result);
			tx.commit();

		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					// Second try catch as the rollback could fail as well
					tx.rollback();
				} catch (HibernateException e1) {
					logger.debug("Error rolling back transaction");
				}
				// throw again the first exception
				// throw e;
			}
			throw e;
		}
	}

	public static <T extends AbstractEntity> T getEntity(Class<T> cls, Long id)
			throws Exception {
		Transaction tx = null;
		Session session = SessionFactoryUtil.getInstance().getCurrentSession();
		try {
			tx = session.beginTransaction();
			T result = (T) session.get(cls, id);
			tx.commit();
			return result;
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					// Second try catch as the rollback could fail as well
					tx.rollback();
				} catch (HibernateException e1) {
					logger.debug("Error rolling back transaction");
				}
				// throw again the first exception
				// throw e;
			}
			throw e;
		}
	}

	public static <T extends AbstractEntity> List<T> getEntities(String name)
			throws Exception {
		Transaction tx = null;
		Session session = SessionFactoryUtil.getInstance().getCurrentSession();
		try {
			tx = session.beginTransaction();
			Query q = session.createQuery("FROM " + name);
			// q.setParameter(1, id);

			@SuppressWarnings("unchecked")
			List<T> results = q.list();
			tx.commit();
			return results;
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					// Second try catch as the rollback could fail as well
					tx.rollback();
				} catch (HibernateException e1) {
					logger.debug("Error rolling back transaction");
				}
				// throw again the first exception
				// throw e;
			}
			throw e;
		}
	}

	public static Collection<Case> getCasesByCatalog(Long id) throws Exception {
		Transaction tx = null;
		Session session = SessionFactoryUtil.getInstance().getCurrentSession();
		try {
			tx = session.beginTransaction();
			Query q = session.createQuery("FROM " + Case.class.getName()
					+ " as p WHERE p.catalogId=:id");
			q.setParameter("id", id);

			@SuppressWarnings("unchecked")
			List<Case> results = q.list();
			tx.commit();
			return results;
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					// Second try catch as the rollback could fail as well
					tx.rollback();
				} catch (HibernateException e1) {
					logger.debug("Error rolling back transaction");
				}
				// throw again the first exception
				// throw e;
			}
			throw e;
		}
	}

	public static Collection<Profile> getProfileByGroup(Long id)throws Exception{
		Transaction tx = null;
		Session session = SessionFactoryUtil.getInstance().getCurrentSession();
		try {
			tx = session.beginTransaction();		
			Query q = session.createQuery("FROM "+Profile.class.getName()+" p WHERE p.groupId=:id");
			q.setParameter("id", id);
			
		    @SuppressWarnings("unchecked")
			List<Profile> results = q.list();			
			tx.commit();
			return results;
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					// Second try catch as the rollback could fail as well
					tx.rollback();
				} catch (HibernateException e1) {
					logger.debug("Error rolling back transaction");
				}
				// throw again the first exception
				// throw e;
			}
			throw e;
		}
	}
	public static Collection<Profile> getProfileByServer(Long id)throws Exception{
		Transaction tx = null;
		Session session = SessionFactoryUtil.getInstance().getCurrentSession();
		try {
			tx = session.beginTransaction();			
			Query q = session.createQuery("FROM "+Profile.class.getName()+" p WHERE p.serverId=:id");
			q.setParameter("id", id);
			
		    @SuppressWarnings("unchecked")
			List<Profile> results = q.list();			
			tx.commit();
			return results;
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					// Second try catch as the rollback could fail as well
					tx.rollback();
				} catch (HibernateException e1) {
					logger.debug("Error rolling back transaction");
				}
				// throw again the first exception
				// throw e;
			}
			throw e;
		}
	}
	
	
	public static Collection<Step> getStepsByCase(long id)throws Exception{
		Transaction tx = null;
		Session session = SessionFactoryUtil.getInstance().getCurrentSession();
		try {
			tx = session.beginTransaction();	
			Query q = session.createQuery("FROM "+Step.class.getName()+" p WHERE p.caseId=:id");
			q.setParameter("id", id);
			
		    @SuppressWarnings("unchecked")
			List<Step> results = q.list();
		    
		    for (Step step : results){
		    	if (step.getRequest() != null) {
		    		int length = step.getRequest().length();
		    		System.out.println(length);
		    	}
		    	if (step.getResponse() != null) {
		    		int length = step.getResponse().length();
		    		System.out.println(length);
		    	}
				////em.detach(giant.getData());
				//session.detach(step);
		    }
			tx.commit();
			return results;
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					// Second try catch as the rollback could fail as well
					tx.rollback();
				} catch (HibernateException e1) {
					logger.debug("Error rolling back transaction");
				}
				// throw again the first exception
				// throw e;
			}
			throw e;
		}
	}
	
	public static void saveSteps(Long caseId, Collection<Step> entities)throws Exception{
		Collection<Step> exists = getStepsByCase(caseId);
		saveEntities(caseId, entities, exists);
		/*for(Step step: entities){
			this.getEntityManager().detach(step.getRequest());
		}*/
	}
	
	public static Collection<Subcase> getSubCasesByCase(Long id)throws Exception{
		Transaction tx = null;
		Session session = SessionFactoryUtil.getInstance().getCurrentSession();
		try {
			tx = session.beginTransaction();			
			Query q = session.createQuery("FROM "+Subcase.class.getName()+" p WHERE p.caseId=:id");
			q.setParameter("id", id);
			
		    @SuppressWarnings("unchecked")
			List<Subcase> results = q.list();			
			tx.commit();
			return results;
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					// Second try catch as the rollback could fail as well
					tx.rollback();
				} catch (HibernateException e1) {
					logger.debug("Error rolling back transaction");
				}
				// throw again the first exception
				// throw e;
			}
			throw e;
		}
	}
	
	public static void saveSubCases(Long caseId, Collection<Subcase> entities)throws Exception{
		Collection<Subcase> exists = getSubCasesByCase(caseId);
		saveEntities(caseId, entities, exists);
	}
	
	
	public static Collection<Result> getRunResultsBySubCase(Long id)throws Exception{
		Transaction tx = null;
		Session session = SessionFactoryUtil.getInstance().getCurrentSession();
		try {
			tx = session.beginTransaction();			
			Query q = session.createQuery("FROM "+Result.class.getName()+" p WHERE p.subCaseId=:id ORDER BY p.date DESC");
			q.setParameter("id", id);
			
		    @SuppressWarnings("unchecked")
			List<Result> results = q.list();
		    for (Result res: results) {
		    	if (res.getResponse() != null) {
		    		int length = res.getResponse().length();
		    		System.out.println(length);
		    	}
		    	//em.detach(res);
		    }
			tx.commit();
			return results;
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					// Second try catch as the rollback could fail as well
					tx.rollback();
				} catch (HibernateException e1) {
					logger.debug("Error rolling back transaction");
				}
				// throw again the first exception
				// throw e;
			}
			throw e;
		}
	}
	
	public static Result getRecentlyRunResultsByStep(Long subcase_id, Long step_id)throws Exception{
		Transaction tx = null;
		Session session = SessionFactoryUtil.getInstance().getCurrentSession();
		try {
			tx = session.beginTransaction();			
			Query q = session.createQuery("FROM "+Result.class.getName()+" p WHERE p.subCaseId=:scid AND p.stepId=:stid ORDER BY p.date DESC");
			q.setParameter("scid", subcase_id);
			q.setParameter("stid", step_id);
			
		    @SuppressWarnings("unchecked")
			List<Result> results = q.list();	
			tx.commit();		
			if(results.size()>0) return results.get(0);
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					// Second try catch as the rollback could fail as well
					tx.rollback();
				} catch (HibernateException e1) {
					logger.debug("Error rolling back transaction");
				}
				// throw again the first exception
				// throw e;
			}
			throw e;
		}
		return null;
	}
	
	
	public static Collection<Param> getParamsBySubcase(Long id)throws Exception{
		Transaction tx = null;
		Session session = SessionFactoryUtil.getInstance().getCurrentSession();
		try {
			tx = session.beginTransaction();		
			Query q = session.createQuery("FROM "+Param.class.getName()+" p WHERE p.subCaseId=:id");
			q.setParameter("id", id);
			
		    @SuppressWarnings("unchecked")
			List<Param> results = q.list();			
			tx.commit();
			return results;
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					// Second try catch as the rollback could fail as well
					tx.rollback();
				} catch (HibernateException e1) {
					logger.debug("Error rolling back transaction");
				}
				// throw again the first exception
				// throw e;
			}
			throw e;
		}
	}
	
	public static void saveParams(Long subcaseId, Collection<Param> entities)throws Exception{
		Collection<Param> exists = getParamsBySubcase(subcaseId);
		saveEntities(subcaseId, entities, exists);
	}
	
}
